# This file is part of Neuroinfo Toolkit.
#
# Neuroinfo Toolkit is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Neuroinfo Toolkit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Neuroinfo Toolkit.  If not, see <http://www.gnu.org/licenses/>.

import os
import unittest
from neuro.filesystem import *
from neuro.exceptions import FileNotFoundException
from neuro.exceptions import IllegalArgumentException

class TestFilesystem(unittest.TestCase):
	def setUp(self):
		## --- filesystem is not a clase
		## --- all methods are static so, nothing to really setup
		self._dir = "../../../dat"

	def test_exists(self):
		## --- bad argument tests
		self.basic(exists)

		## --- file exists
		self.assertTrue(exists(os.path.join(self._dir, "existing.txt")))

		## --- directory exists
		self.assertTrue(exists(os.path.join(self._dir, "directory")))

		## --- file/directory does not exist
		self.assertFalse(exists(os.path.join(self._dir, "non-existent.txt")))

		## --- file is within a protected location
		self.assertFalse(exists(os.path.join(self._dir, "dir-noread", "file.txt")))

	def test_isReadable(self):
		## --- bad argument tests
		self.basic(isReadable)

		## --- readable file
		self.assertTrue(isReadable(os.path.join(self._dir, "existing.txt")))

		## --- readable directory
		self.assertTrue(isReadable(os.path.join(self._dir, "directory")))

		## --- unreadable directory
		self.assertFalse(isReadable(os.path.join(self._dir, "dir-noread")))

		## --- unreadable file
		self.assertFalse(isReadable(os.path.join(self._dir, "file-noread.txt")))

		## --- non-existent file or directory
		self.assertRaises(FileNotFoundException, isReadable, os.path.join(self._dir, "non-existent"))

	def test_filePutContents(self):
		## --- no arguments
		self.assertRaises(TypeError, filePutContents)

#		self.assertRaises(IllegalArgumentException, filePutContents)

	def test_isWritable(self):
		## --- bad argument tests
		self.basic(isWritable)

		## --- writeable file
		self.assertTrue(isWritable(os.path.join(self._dir, "existing.txt")))

		## --- writeable directory
		self.assertTrue(isWritable(os.path.join(self._dir, "directory")))

		## --- unwriteable directory
		self.assertFalse(isWritable(os.path.join(self._dir, "dir-noread")))

		## --- unwriteable file
		self.assertFalse(isWritable(os.path.join(self._dir, "file-noread.txt")))

		## --- non-existent file or directory
		self.assertRaises(FileNotFoundException, isWritable, os.path.join(self._dir, "non-existent"))

	def test_isExecutable(self):
		## --- bad argument tests
		self.basic(isExecutable)

		## --- executable file
		self.assertTrue(isExecutable(os.path.join(self._dir, "existing.txt")))

		## --- executable directory
		self.assertTrue(isExecutable(os.path.join(self._dir, "directory")))

		## --- non-executable file
		self.assertFalse(isExecutable(os.path.join(self._dir, "file-noread.txt")))

		## --- non-executable directory
		self.assertFalse(isExecutable(os.path.join(self._dir, "dir-noread")))

		## --- non-existent file or directory
		self.assertRaises(FileNotFoundException, isExecutable, os.path.join(self._dir, "non-existent"))

	def test_isRegularFile(self):
		## --- bad argument tests
		self.basic(isRegularFile)

		## --- file (regular)
		self.assertTrue(isRegularFile(os.path.join(self._dir, "existing.txt")))

		## --- directory (non-regular)
		self.assertFalse(isRegularFile(os.path.join(self._dir, "directory")))

		## --- non-existent file or directory
		self.assertRaises(FileNotFoundException, isRegularFile, os.path.join(self._dir, "non-existent"))

	def test_fileGetContents(self):
		## --- bad argument tests
		self.basic(fileGetContents)

		## --- read file
		self.assertEqual(fileGetContents(os.path.join(self._dir, "existing.txt")), "Hello, World!")

		## --- unreadable
		self.assertRaises(IOException, fileGetContents, os.path.join(self._dir, "file-noread.txt"))

		## --- directory
		self.assertRaises(IOError, fileGetContents, os.path.join(self._dir, "directory"))

	def test_getExtension(self):
		## --- bad argument tests
		self.basic(getExtension)

		## --- filename
		self.assertEqual(getExtension("~/dat/file.txt"), ".txt")

		## --- filename, no extension
		self.assertEqual(getExtension("./dat/dir-noread/foo"), "")

		## --- filename, dual extensions
		self.assertEqual(getExtension("./dat/foo.nii.gz"), ".gz")

	def test_basename(self):
		## --- bad argument tests
		self.basic(basename)

		## --- get all sorts of possible basenames
		self.assertEqual(basename("~/foo"), "foo")
		self.assertEqual(basename("~/foo/"), "foo")
		self.assertEqual(basename("/foo"), "foo")
		self.assertEqual(basename("foo/"), "foo")
		self.assertEqual(basename("foo"), "foo")
		self.assertEqual(basename("/foo/"), "foo")
		self.assertEqual(basename("./foo/"), "foo")
		self.assertEqual(basename("./foo/bar"), "bar")
		self.assertEqual(basename("./foo/bar/"), "bar")
		self.assertEqual(basename("~/foo/bar"), "bar")
		self.assertEqual(basename("~/foo/bar/"), "bar")
		self.assertEqual(basename("/foo/bar"), "bar")
		self.assertEqual(basename("/foo/bar/"), "bar")
		self.assertEqual(basename("foo/bar"), "bar")
		self.assertEqual(basename("foo/bar/"), "bar")

	def test_dirname(self):
		## --- bad argument tests
		self.basic(dirname)

		cwd = os.getcwd()
		home = os.getenv("HOME")

		## --- get all sorts of possible basenames
		self.assertEqual(dirname("~/foo"), home)
		self.assertEqual(dirname("~/foo/"), home)
		self.assertEqual(dirname("/foo"), "/")
		self.assertEqual(dirname("foo/"), cwd)
		self.assertEqual(dirname("foo"), cwd)
		self.assertEqual(dirname("/foo/"), "/")
		self.assertEqual(dirname("./foo/"), cwd)
		self.assertEqual(dirname("./foo/bar"), os.path.join(cwd, "foo"))
		self.assertEqual(dirname("./foo/bar/"), os.path.join(cwd, "foo"))
		self.assertEqual(dirname("~/foo/bar"), os.path.join(home, "foo"))
		self.assertEqual(dirname("~/foo/bar/"), os.path.join(home, "foo"))
		self.assertEqual(dirname("/foo/bar"), "/foo")
		self.assertEqual(dirname("/foo/bar/"), "/foo")
		self.assertEqual(dirname("foo/bar"), os.path.join(cwd, "foo"))
		self.assertEqual(dirname("foo/bar/"), os.path.join(cwd, "foo"))

	def test_delete(self):
		## --- bad arguments
		self.basic(delete)

		## --- delete a regular file
		if(not exists(os.path.join(self._dir, "deleteme"))):
			poke(os.path.join(self._dir, "deleteme"), True)

		self.assertTrue(exists(os.path.join(self._dir, "deleteme")))
		assert delete(os.path.join(self._dir, "deleteme")) is None
		self.assertFalse(exists(os.path.join(self._dir, "deleteme")))

		## --- delete a directory
		if(not exists(os.path.join(self._dir, "deleteme_dir"))):
			mkdir(os.path.join(self._dir, "deleteme_dir"))

		self.assertTrue(exists(os.path.join(self._dir, "deleteme_dir")))
		assert delete(os.path.join(self._dir, "deleteme_dir")) is None
		self.assertFalse(exists(os.path.join(self._dir, "deleteme_dir")))

		## --- delete a full directory without recursion
		if(not exists(os.path.join(self._dir, "test", "me"))):
			mkdir(os.path.join(self._dir, "test/me"))

		self.assertRaises(IOException, delete, os.path.join(self._dir, "test"))

		## --- delete full directory with recursion
		assert delete(os.path.join(self._dir, "test"), True) is None

		## --- delete protected directory
		self.assertRaises(IOException, delete, os.path.join(self._dir, "dir-noread"))

	def test_mkdir(self):
		## --- no arguments
		self.basic(mkdir)
		
		## --- make a directory
		if(exists(os.path.join(self._dir, "bar"))):
			delete(os.path.join(self._dir, "bar"))

		self.assert_(mkdir(os.path.join(self._dir, "bar")))
		
		## --- make a directory over one that exists
		self.assertRaises(FileExistsException, mkdir, os.path.join(self._dir, "foo"))

		## --- make a directory in an unwritable directory
		self.assertRaises(IOException, mkdir, os.path.join(self._dir, "dir-noread", "dir"))

		## --- make a directory with special chars in name
		if(exists(os.path.join(self._dir, "bar\ biz"))):
			delete(os.path.join(self._dir, "bar\ biz"))

		self.assert_(mkdir(os.path.join(self._dir, "bar\ biz")))

	def test_getFilePermissions(self):
		self.basic(getFilePermissions)

		## --- non-existent file
		self.assertRaises(FileNotFoundException, getFilePermissions, os.path.join(self._dir, "non-existent"))

		## --- file within a protected directory
		self.assertRaises(FileNotFoundException, getFilePermissions, os.path.join(self._dir, "dir-noread", "file.txt"))

		## --- ok file
		self.assertEqual(getFilePermissions(os.path.join(self._dir, "existing.txt")), "0755")

		## --- ok directory
		self.assertEqual(getFilePermissions(os.path.join(self._dir, "dir-noread")), "0")

	def test_percentFull(self):
		self.basic(percentFull)

		assert percentFull(os.path.join(self._dir, "existing.txt")) is not None

	def basic(self, method):
		## --- no arguments
		self.assertRaises(TypeError, method)

		## --- bad argument
		self.assertRaises(IllegalArgumentException, method, list())
		self.assertRaises(IllegalArgumentException, method, "")

	def tearDown(self):
		pass

unittest.main()
